#ifndef _FIXED_PTC_H_
#define _FIXED_PTC_H_

/*
 * Signed 32-bit fixed point number library for the 24.8 format.
 * The specific limits are -8388608.999... to 8388607.999... and the
 * most precise number is 0.00390625. In practice, you should not count
 * on working with numbers larger than a million or to the precision
 * of more than 2 decimal places. Make peace with the fact that PI
 * is 3.14 here. :)
 *
 * Since the precision is relatively low, many complex functions (more
 * complex than div & mul) take a large hit on the precision of the
 * end result, because errors in precision accumulate.
 * This loss of precision can be lessened by increasing the number of
 * bits dedicated to the fraction part, but at the loss of range.
 *
 * Adventurous users might utilize this library to build two data types:
 * one which has the range, and one which has the precision, and carefully
 * convert between them (including adding two number of each type to produce
 * a simulated type with a larger range and precision).
 *
 * The ideas and algorithms have been cherry-picked from a large number
 * of previous implementations available on the Internet.
 */

/*-
 * Copyright (c) 2010 Ivan Voras <ivoras@freebsd.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "basictype.h"

template<int F> struct power10 
{
	static const int value = 10 * power10<F-1>::value;
};

template <> struct power10<0> 
{
	static const int value = 1;
};

template<size_t P>
class fixed_pt_impl
{
public:
	fixed_pt_impl():_val(0)
	{
	}
	fixed_pt_impl(int v)
	{
		_val = v * power10<P>::value;
	}
	fixed_pt_impl(INT64 v)
	{
		_val = v * power10<P>::value;
	}
	fixed_pt_impl(float v)
	{
		_val = (v+1e-5) * power10<P>::value;
	}

	fixed_pt_impl(double v)
	{
		_val = (INT64)(v+1e-5) * power10<P>::value;
	}

	double to_double()
	{
		return double(_val)/power10<P>::value;
	}

	bool operator == (const fixed_pt_impl& r) const
	{
		return _val == r._val;
	}
	bool operator != (const fixed_pt_impl& r) const
	{
		return _val != r._val;
	}
	bool operator < (const fixed_pt_impl& r) const
	{
		return _val < r._val;
	}
	bool operator > (const fixed_pt_impl& r) const
	{
		return _val > r._val;
	}
	bool operator <= (const fixed_pt_impl& r) const
	{
		return _val <= r._val;
	}
	bool operator >= (const fixed_pt_impl& r) const
	{
		return _val >= r._val;
	}


	const fixed_pt_impl operator +(const fixed_pt_impl& r) const
	{
		fixed_pt_impl ret;
		ret._val = _val + r._val;
		return ret;
	}

	const fixed_pt_impl operator -(const fixed_pt_impl& r) const
	{
		fixed_pt_impl ret;
		ret._val = _val - r._val;
		return ret;
	}

	const fixed_pt_impl operator *(const fixed_pt_impl& r) const
	{
		fixed_pt_impl ret;
		ret._val = _val * r._val /power10<P>::value;
		return ret;
	}

	const fixed_pt_impl operator /(const fixed_pt_impl& r) const
	{
		fixed_pt_impl ret;
		ret._val = _val*power10<P>::value/r._val;
		return ret;
	}

	void str(char *s)
	{//TODO

	}

	//non-thread safe
	const char* c_str()
	{
		static char s[20];

		str(s);
		return (s);
	}

private:
	INT64 _val;
	static int _scale;
};

#endif
